Skip to content

Fix phpstan/phpstan#9844: Calling a static method over non-generic class-string results in ErrorType#5418

Closed
phpstan-bot wants to merge 3 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-3gwsl2g
Closed

Fix phpstan/phpstan#9844: Calling a static method over non-generic class-string results in ErrorType#5418
phpstan-bot wants to merge 3 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-3gwsl2g

Conversation

@phpstan-bot
Copy link
Copy Markdown
Collaborator

Summary

When calling a static method on a non-generic class-string variable (e.g. $class::foo() where $class is class-string), PHPStan returned *ERROR* type instead of mixed. This is incorrect because class-string represents any class, and the method could exist on whatever class it turns out to be at runtime.

Changes

  • Modified src/Analyser/ExprHandler/StaticCallHandler.php to track when the static call target comes from a class-string type, and return mixed instead of ErrorType when the method might exist on the type
  • Added regression test tests/PHPStan/Analyser/nsrt/bug-9844.php

Root cause

The flow was:

  1. class-string gets converted to ObjectWithoutClassType via getObjectTypeOrClassStringObjectType()
  2. ObjectWithoutClassType::hasMethod() returns TrinaryLogic::MAYBE (the method might exist)
  3. MutatingScope::filterTypeWithMethod() requires hasMethod()->yes(), so it returns null
  4. MethodCallReturnTypeHelper::methodCallReturnType() returns null
  5. StaticCallHandler falls back to ErrorType

The fix detects when the caller is a class-string type and the target type says the method might exist (MAYBE), returning mixed instead of ErrorType. This is consistent with how calling methods on mixed returns mixed.

Test

Added tests/PHPStan/Analyser/nsrt/bug-9844.php which asserts that $class::foo() where $class: class-string returns mixed.

Fixes phpstan/phpstan#9844

…mixed instead of ErrorType

- When calling a static method on a non-generic class-string variable, return mixed instead of ErrorType
- The fix only applies to class-string types, not to named class or typed object expressions
- New regression test in tests/PHPStan/Analyser/nsrt/bug-9844.php
- Root cause: class-string converts to ObjectWithoutClassType which has hasMethod() = MAYBE, causing filterTypeWithMethod to bail out and fall back to ErrorType
Copy link
Copy Markdown
Contributor

@VincentLanglet VincentLanglet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep the ErrorType for $class::foo() and instead, report an error to be consistent with

/**
     * @param object $class
     */
	public function sayHello2(object $class): void
	{
		\PHPStan\dumpType($class::foo());
	}

which report

Call to an undefined static method object::foo().

Keep ErrorType for `$class::foo()` on non-generic class-string,
consistent with how `object::foo()` reports an error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@phpstan-bot
Copy link
Copy Markdown
Collaborator Author

Already handled — make tests passed (11736 tests, 78977 assertions), and the commit has been pushed.

Copy link
Copy Markdown
Contributor

@VincentLanglet VincentLanglet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a RuleTest for

	/**
     * @param class-string $class
     */
	public function sayHello(string $class): void
	{
		$class::foo();
	}

	/**
     * @param object $class
     */
	public function sayHello2(object $class): void
	{
		$class::foo();
	}

and ensure BOTH report a static.notFound error

Static method calls on bare class-string (e.g. $class::foo()) now
report "Call to an undefined static method class-string::foo()" instead
of silently returning no errors. This is consistent with how object
type static calls already report the error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@phpstan-bot
Copy link
Copy Markdown
Collaborator Author

All four background tasks (2x tests, 2x phpstan) completed successfully. Everything is green and pushed.

@VincentLanglet VincentLanglet deleted the create-pull-request/patch-3gwsl2g branch April 11, 2026 15:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants